package cn.mydsl.restful

import com.mysql.cj.jdbc.exceptions.CommunicationsException
import io.vertx.core.Vertx
import io.vertx.core.http.HttpHeaders
import io.vertx.core.json.Json
import io.vertx.core.json.JsonObject
import io.vertx.ext.auth.jwt.JWTAuth
import io.vertx.ext.auth.jwt.JWTOptions
import io.vertx.ext.jdbc.JDBCClient
import io.vertx.ext.web.Cookie
import io.vertx.ext.web.RoutingContext
import kotlin.properties.Delegates

class LoginDto(loginName: String = "", loginSecret: String = "", clientId: String? = null, verifyCode: String? = null) {
    var loginName: String = ""
        get() {
            return field.trim().replace("'", "''")
        }
    var loginSecret: String = ""
        get() {
            return field.trim().replace("'", "''")
        }
    var clientId: String? = null
        get() {
            return field?.trim()?.replace("'", "''")
        }
    var verifyCode: String? = null
        get() {
            return field?.trim()?.replace("'", "''")
        }

    fun valid(): Boolean {
        return loginName.isNotEmpty() && loginSecret.trim().isNotEmpty()
    }

    init {
        this.loginName = loginName
        this.loginSecret = loginSecret
        this.clientId = clientId
        this.verifyCode = verifyCode
    }
}

class UserResource(val jdbcClient: JDBCClient, val vertx: Vertx) {
    companion object {
        val config = JsonObject().put("keyStore", JsonObject()
                .put("path", "keystore.jceks")
                .put("type", "jceks")
                .put("password", "23050210"))
        var jwtAuth: JWTAuth by Delegates.notNull()
    }

    init {
        try {
            jwtAuth = JWTAuth.create(this.vertx, config)
        } catch (ex: Exception) {
            ex.toErroMsg("JWT初始化失败", ErroType.InitExcp)
        }
    }

    fun Login(routingContext: RoutingContext): Unit {
        try {
            val lginDto = Json.decodeValue(routingContext.bodyAsString, LoginDto::class.java)
            if (lginDto.valid()) {
                jdbcClient.getConnection({ ar ->
                    if (ar.failed()) {
                        val erroMsg = ar.cause().toErroMsg("从JDBC连接池获取连接失败", ErroType.SqlConExcp)
                        erroMsg.printJsonString()
                        routingContext.response().erro(erroMsg)
                    } else {
                        val connection = ar.result()
                        val sql1 = "SELECT `t1`.`id` AS `uid`,`t1`.`OrgId` AS `oid`,`t2`.`JobId` AS `jid`,`t3`.`OrgClassId` AS `ocid`,`t3`.`status` AS orgStatus FROM `auth_db`.`User` `t1` left join `auth_db`.`UserJob` `t2` ON `t1`.`id`=`t2`.`UserId`  left join `auth_db`.`Org` `t3` ON `t1`.`OrgId`=`t3`.`id` WHERE `t1`.`status`>=0  AND (`t1`.`mobileNo`='${lginDto.loginName}' OR `t1`.`userName`='${lginDto.loginName}' OR  `t1`.`idCard`='${lginDto.loginName}') AND `t1`.`password`='${lginDto.loginSecret}';"
                        connection.query(sql1, { result ->
                            if (result.failed()) {
                                println("sql：${sql1}")
                                if (result.cause() is CommunicationsException) {
                                    val erroMsg = result.cause().toErroMsg("数据库连接丢失", ErroType.SqlConExcp)
                                    erroMsg.printJsonString()
                                    routingContext.response().erro(erroMsg)
                                } else {
                                    val erroMsg = result.cause().toErroMsg("执行sql失败", ErroType.SqlExecExcp)
                                    erroMsg.printJsonString()
                                    routingContext.response().erro(erroMsg)
                                }
                            } else {
                                val rows1 = result.result().getRows()
                                if (rows1.size >= 1) {
                                    //验证用户密码成功
                                    val uid = rows1[0].getString("uid")
                                    val orgStatus = rows1[0].getInteger("orgStatus",-1)
                                    val oid = rows1[0].getString("oid")
                                    //个人身份的工作
                                    var jidForPersonal = ""
                                    for (row in rows1) {
                                        if (row.getString("jid") != null) {
                                            jidForPersonal += "${row.getString("jid")},"
                                        }
                                    }
                                    jidForPersonal = jidForPersonal.substringBeforeLast(",")
                                    val ocid = rows1[0].getString("ocid")
                                    val jwtOptions = JWTOptions()
                                    //jwtOptions.expiresInMinutes=7*24*60 //7天过期
                                    jwtOptions.algorithm = "RS256" //使用keystore内采用RSA非对称算法的RS256秘钥
                                    val jsonObject = JsonObject()
                                    //组织oid有效，且状态可用
                                    if (oid != null && oid != "personal" && orgStatus>=0) {
                                        val sql2 = "SELECT `t1`.`id` AS `eid`,`t2`.`JobId` AS `jid` FROM `auth_db`.`Emp` `t1` left join `auth_db`.`EmpJob` `t2` ON `t1`.`id`=`t2`.`EmpId` WHERE `t1`.`status`>=0 AND `t1`.`OrgId`='$oid' AND `t1`.`UserId`='$uid'"
                                        connection.query(sql2, { result ->
                                            if (result.failed()) {
                                                println("sql：${sql2}")
                                                if (result.cause() is CommunicationsException) {
                                                    val erroMsg = result.cause().toErroMsg("数据库连接丢失", ErroType.SqlConExcp)
                                                    erroMsg.printJsonString()
                                                    routingContext.response().erro(erroMsg)
                                                } else {
                                                    val erroMsg = result.cause().toErroMsg("执行sql失败", ErroType.SqlExecExcp)
                                                    erroMsg.printJsonString()
                                                    routingContext.response().erro(erroMsg)
                                                }
                                            } else {
                                                val rows2 = result.result().getRows()
                                                if (rows2.size >= 1) {
                                                    //以组织里的员工身份登录,token内包含 员工eid 组织oid 工作jid
                                                    jsonObject.put("uid", uid)
                                                    jsonObject.put("oid", oid)
                                                    jsonObject.put("eid", rows2[0].getString("eid"))
                                                    //员工身份的工作
                                                    var jid = ""
                                                    for (row in rows2) {
                                                        if (row.getString("jid") != null) {
                                                            jid += "${row.getString("jid")},"
                                                        }
                                                    }
                                                    jid = jid.substringBeforeLast(",")
                                                    if (jid.isNotEmpty()) {
                                                        jsonObject.put("jid", jid)
                                                    }
                                                    jsonObject.put("ocid", ocid)
                                                    val token = jwtAuth.generateToken(jsonObject, jwtOptions)
                                                    routingContext.addCookie(Cookie.cookie(HttpHeaders.AUTHORIZATION.toString(), "bearer%20${token}").setMaxAge(Int.MAX_VALUE.toLong()).setPath("/").setHttpOnly(true));
                                                    jsonObject.put("accessToken", token)
                                                    jsonObject.put("tokenType", "bearer")
                                                    routingContext.response().html(jsonObject.toJsonString())
                                                } else {
                                                    //OrgId无效或不是它的员工，则以个人身份登录,token内包含个人uid，无组织信息
                                                    jsonObject.put("uid", uid)
                                                    if (jidForPersonal.isNotEmpty()) {
                                                        jsonObject.put("jid", jidForPersonal)
                                                    }
                                                    val token = jwtAuth.generateToken(jsonObject, jwtOptions)
                                                    routingContext.addCookie(Cookie.cookie(HttpHeaders.AUTHORIZATION.toString(), "bearer%20${token}").setMaxAge(Int.MAX_VALUE.toLong()).setPath("/").setHttpOnly(true));
                                                    jsonObject.put("accessToken", token)
                                                    jsonObject.put("tokenType", "bearer")
                                                    routingContext.response().html(jsonObject.toJsonString())
                                                }
                                            }//获取员工信息
                                        })
                                    } else {
                                        //OrgId为空或组织是个人，则以个人身份登录,token内包含个人uid，无组织信息
                                        jsonObject.put("uid", uid)
                                        if (jidForPersonal.isNotEmpty()) {
                                            jsonObject.put("jid", jidForPersonal)
                                        }
                                        val token = jwtAuth.generateToken(jsonObject, jwtOptions)
                                        routingContext.addCookie(Cookie.cookie(HttpHeaders.AUTHORIZATION.toString(), "bearer%20${token}").setMaxAge(Int.MAX_VALUE.toLong()).setPath("/").setHttpOnly(true));
                                        jsonObject.put("accessToken", token)
                                        jsonObject.put("tokenType", "bearer")
                                        routingContext.response().html(jsonObject.toJsonString())
                                    }
                                } else {
                                    //验证用户密码失败
                                    routingContext.response().erro(ErroMsg("用户或密码错误", ErroType.InvalidParam))
                                }
                                connection.close()
                            }
                        })
                    }
                })
            } else {
                routingContext.response().erro(ErroMsg("用户密码不能为空", ErroType.InvalidParam))
            }
        } catch (ex: Exception) {
            var erroMsg = ex.toErroMsg("输入不合法", ErroType.InvalidParam)
            erroMsg.printJsonString()
            routingContext.response().erro(erroMsg)
        }
    }

    fun Logout(routingContext: RoutingContext): Unit {
        routingContext.addCookie(Cookie.cookie("Authorization", "").setMaxAge(0).setPath("/").setHttpOnly(true));
        routingContext.response().html("1")
    }
}

